﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Vowei.Data;
using Vowei.Data.Models;
using Vowei.Data.Helpers;
using Vowei.Core.Models;
using Vowei.Web.Models;
using Vowei.Web.Helpers;

namespace vowei.test
{
    [TestClass]
    public class FullTreeTest : TestBase
    {
        [TestMethod]
        public void GetMilestoneTicketsTest()
        {
            using (var context = new VoweiContextImpl())
            {
                var milestone = GetDefaultProject(context);
                var tree = milestone.AllTickets(new VoweiContext(context));

                Assert.AreNotEqual(0, tree.Count());
            }
        }

        public static List<T> ConvertToList<T>(T root) where T : IContainer<T>
        {
            var result = new List<T>();
            var stack = new Stack<T>(root.Children);

            while (stack.Count > 0)
            {
                var obj = stack.Pop();
                result.Add(obj);
                foreach (var item in obj.Children)
                {
                    stack.Push(item);
                }
            }

            return result;
        }

        [TestMethod]
        public void MilestoneProgressCreateFromTest()
        {
            using (var contextImpl = new VoweiContextImpl())
            {
                var project = GetDefaultUnModifiedProject(contextImpl);
                var progresses = MilestoneProgress.CreateFrom(project, new VoweiContext(contextImpl));

                var progQueue = ConvertToList(progresses);
                var msQueue = ConvertToList<Milestone>(project);
                Assert.AreEqual(msQueue.Count, progQueue.Count);

                var expectedTicketsCount = progresses.Children.Sum(p => p.TicketCount);
                var actualTicketsCount = progQueue.Sum(p => p.TicketCount);
                Assert.AreEqual(expectedTicketsCount, actualTicketsCount);

                var expectedActiveTicketsCount = progresses.Children.Sum(p => p.ActiveTicketCount);
                var actualActiveTicketsCount = progQueue.Sum(p => p.ActiveTicketCount);
                Assert.AreEqual(expectedActiveTicketsCount, actualActiveTicketsCount);

                var expectedClosedTicketsCount = progresses.Children.Sum(p => p.ClosedTicketCount);
                var actualClosedTicketsCount = progQueue.Sum(p => p.ClosedTicketCount);
                Assert.AreEqual(expectedClosedTicketsCount, actualClosedTicketsCount);

                var children = progresses.Children.ToArray();
                Array.Sort(children, (left, right) => left.ActiveTicketCount - right.ActiveTicketCount);

                for (int i = 0; i < progQueue.Count - 1; ++i)
                {
                    if (i == children.Length - 1)
                        Assert.AreNotEqual(0, children[i].ActiveTicketCount);
                    else
                        Assert.AreEqual(0, children[i].ActiveTicketCount);

                    if (children[i].ClosedTicketCount == 0)
                        Assert.AreEqual(children[i].ClosedTicketCount, children[i + 1].ClosedTicketCount);
                    else
                        Assert.AreNotEqual(children[i].ClosedTicketCount, children[i + 1].ClosedTicketCount);
                }
            }
        }

        [TestMethod]
        [Description("测试返回针对层次结构，例如保留里程碑的层次结构，返回并执行统计的方法")]
        public void HierarchyTimelineStatisticsTest()
        {
            using (var contextImpl = new VoweiContextImpl())
            {
                var project = GetDefaultProject(contextImpl);

                // Linq to Entity 不能将下面的代码转换成SQL语句
                // -----------------------------------------------------------------------------------------------------------
                //var milestones = from node in context.TimelineNodes.FullTree(milestone)
                //                 join milestone in context.Milestones.Include("Children") on node.NodeId equals milestone.ID
                //                 select new
                //                 {
                //                     Milestone = milestone,
                //                     Tickets = from n in context.TimelineNodes.FullTree(milestone)
                //                               join ticket in context.Tickets on n.NodeId equals ticket.ID
                //                               select ticket
                //                 };
                // -----------------------------------------------------------------------------------------------------------
                var context = new VoweiContext(contextImpl);
                var ms = project.AllMilestones(context);
                var msQuery = from m in ms.ToList()
                              select new
                              {
                                  Milestone = m,
                                  Tickets = m.AllTickets(context)
                              };

                var milestones = msQuery.ToList();

                var progresses = new List<MilestoneProgress>(milestones.Count());
                for (int i = 0; i < milestones.Count(); ++i)
                {
                    var m = milestones[i];
                    var progress = new MilestoneProgress()
                    {
                        Milestone = m.Milestone,
                        ActiveTicketCount = m.Tickets.Count(t => !t.ClosedDate.HasValue),
                        ClosedTicketCount = m.Tickets.Count(t => t.ClosedDate.HasValue)
                    };

                    Assert.AreEqual(m.Tickets.Count(), progress.ActiveTicketCount + progress.ClosedTicketCount);
                    progresses.Add(progress);
                }

                foreach (var m in milestones)
                {
                    var progress = progresses.First(p => p.Milestone == m.Milestone);

                    foreach (var child in m.Milestone.Children)
                    {
                        progress.Children.Add(
                            progresses.First(p => p.Milestone == m.Milestone));
                    }
                }

                for (int i = 0; i < milestones.Count(); ++i)
                {
                    Assert.AreEqual(milestones.ElementAt(i).Milestone.Children.Count(),
                        progresses[i].Children.Count);
                }
            }
        }
        
        [TestMethod]
        public void GetUpRequirementBasicTest()
        {
            using (var impl = new VoweiContextImpl())
            {
                var project = GetDefaultUnModifiedProject(impl);
                var context = new VoweiContext(impl);
                var tasks = project.AllTasks(context);
                var task = tasks.First();

                var requirement = task.GetUpRequirement(context);
                Assert.IsNotNull(requirement);
                Assert.AreEqual("Plan the Process", requirement.Title);

                var requirements = project.AllRequirements(context);
                Assert.IsTrue(requirements.Any(r => r.ID == requirement.ID));

                var actualTasks = requirement.AllTasks(context);
                Assert.IsTrue(actualTasks.Any(t => t.ID == task.ID));
            }
        }

        [TestMethod]
        public void GetGetBelongingMilestoneBasicTest()
        {
            using (var impl = new VoweiContextImpl())
            {
                var project = GetDefaultUnModifiedProject(impl);
                var context = new VoweiContext(impl);
                var tasks = project.AllTasks(context);
                var task = tasks.First();

                var milestone = task.GetBelongingMilestone(context);
                Assert.IsNotNull(milestone);
                var milestones = project.AllMilestones(context);
                Assert.IsTrue(milestones.Any(m => m.ID == milestone.ID));

                var requirements = project.AllRequirements(context);
                var requirement = requirements.First();

                milestone = task.GetBelongingMilestone(context);
                Assert.IsNotNull(milestone);
                Assert.IsTrue(milestones.Any(m => m.ID == milestone.ID));
            }
        }
    }
}
